package service

import (
	"errors"
	"fmt"
	"gitee.com/gitee-go/core"
	"gitee.com/gitee-go/core/bean/repobean"
	"gitee.com/gitee-go/core/common"
	"gitee.com/gitee-go/core/dbcore"
	"gitee.com/gitee-go/core/model/pipeline"
	"gitee.com/gitee-go/core/thirdapi"
	"gitee.com/gitee-go/server/comm"
	"gitee.com/gitee-go/utils"
	"runtime/debug"
	"strconv"
	"time"
)

/**
刷新仓库
*/
func RefreshRepo(tu *pipeline.TUserToken, page int) (rterr error) {
	ts := time.Now()
	defer func() {
		core.Log.Debugf("RefreshRepo (%s) page:%d end time:%.4fs", tu.Nick, page, time.Since(ts).Seconds())
		if err := recover(); err != nil {
			rterr = fmt.Errorf("recover:%v", err)
			core.LogPnc.Errorf("RefreshRepo recover:%+v", err)
			core.LogPnc.Errorf("%s", string(debug.Stack()))
		}
	}()
	core.Log.Debugf("RefreshRepo 刷新仓库中 user:%v,page:%d", tu.Nick, page)
	db := comm.DBMain.GetDB()
	appinfo, err := GetsParamOAuthKey()
	if err != nil {
		core.Log.Errorf("RefreshRepos.GetsParamOAuthKey err : %v", err)
		return errors.New("刷新仓库失败,OAuthKey错误")
	}
	k, info := appinfo.DefAppInfo()
	c, err := comm.GetThirdApi(k, info.SourceHost)
	if err != nil {
		core.Log.Errorf("RefreshRepos.GetThirdApi err : %v", err)
		return errors.New("刷新仓库失败,API错误")
	}
	ls, err := c.Repositories.GetRepos(tu.AccessToken, tu.Name, common.All, common.Pushed, common.OrderDesc, page, 20)
	if err != nil {
		core.Log.Errorf("RefreshRepos.GetRepos err : %v", err)
		return errors.New("刷新仓库失败,请检查用户权限")
	}
	if len(ls.Ropes) <= 0 {
		return fmt.Errorf("%v RefreshRepo data len is 0", tu.Nick)
	}
	// 循环仓库,更新表,更新用户关系,有可能此用户被移除仓库
	for _, v := range ls.Ropes {
		core.Log.Debugf("start put repo openid:%d,name:%s", v.Id, v.FullName)
		tr := &pipeline.TRepo{}
		b, _ := db.Where("openid = ?", v.Id).Get(tr)
		if !b {
			tr.Id = utils.NewXid()
			tr.Owner = v.Owner
			tr.Name = v.Name
			tr.FullName = v.FullName
			tr.Path = v.Path
			tr.Namespace = v.Namespace
			tr.Openid = v.Id
			tr.Url = v.HtmlURL
			tr.RepoType = v.RepoType
			tr.RefreshTime = time.Now()
			tr.UpdateTime = time.Now()
			tr.CreateTime = time.Now()
			_, err = db.Insert(tr)
			if err != nil {
				core.Log.Errorf("RefreshRepos.GetRepos TRepo Update err : %v", err)
				return fmt.Errorf("刷新仓库失败,请重试")
			}
		} else {
			tr.FullName = v.FullName
			tr.Name = v.Name
			tr.Path = v.Path
			tr.Openid = v.Id
			tr.Namespace = v.Namespace
			tr.Url = v.HtmlURL
			_, err = db.Cols("full_name , name , path , namespace, url").
				Where("id = ?", tr.Id).Update(tr)
		}
		if err != nil {
			core.Log.Errorf("RefreshRepos.GetRepos TRepo Update err : %v", err)
			return fmt.Errorf("刷新仓库失败,请重试")
		}
		if tr.Deleted != 0 {
			continue
		}
		tur := &pipeline.TUserRepo{
			Id:     utils.NewXid(),
			RepoId: tr.Id,
			UserId: tu.Uid,
		}
		_, err = db.Insert(tur)
		if err != nil {
			core.Log.Errorf("RefreshRepos.GetRepos TUserRepo Insert err : %v", err)
			return fmt.Errorf("刷新仓库失败,请重试")
		}
		err = RefreshBranches(tu.AccessToken, tr)
		if err != nil {
			core.Log.Errorf("RefreshRepos.RefreshBranches err : %v", err)
			continue
		}
	}
	return nil
}

// 刷新分支
func RefreshBranches(accessToken string, tr *pipeline.TRepo) (errs error) {
	db := comm.DBMain.GetDB()
	appinfo, err := GetsParamOAuthKey()
	if err != nil {
		core.Log.Errorf("RefreshBranches.GetsParamOAuthKey err : %v", err)
		return err
	}
	k, info := appinfo.DefAppInfo()
	cl, err := comm.GetThirdApi(k, info.SourceHost)
	if err != nil {
		core.Log.Errorf("RefreshBranches.GetThirdApi err : %v", err)
		return err
	}
	branches, err := cl.Repositories.GetRepoBranches(accessToken, tr.Namespace, tr.Path)
	if err != nil {
		core.Log.Errorf("RefreshRepos.GetRepoBranches  err : %v", err)
		return err
	}

	if len(branches) <= 0 {
		return nil
	} // 接口返回分支为0,就返回
	for _, branch := range branches {
		tpb := &pipeline.TPipelineBranch{}
		get, err := db.Where("repo_id = ? and name = ?", tr.Id, branch.Name).Get(tpb)
		if err != nil {
			core.Log.Errorf("RefreshRepos.GetRepos TPipelineBranch db err : %v", err)
			return err
		}
		if !get {
			tpb.Id = utils.NewXid()
			tpb.Name = branch.Name
			tpb.CreateTime = time.Now()
			tpb.RepoId = tr.Id
			_, err := db.Insert(tpb)
			if err != nil {
				core.Log.Errorf("RefreshRepos.GetRepos TPipelineBranch Insert db err : %v", err)
				return err
			}
		}

	}
	return nil
}

// 激活仓库
func ActiveRepo(user *pipeline.TUser, openid string) (errs error) {
	db := comm.DBMain.GetDB()
	tu := &pipeline.TUserToken{
		Uid: user.Id,
	}
	get, err := db.Get(tu)
	if err != nil {
		core.Log.Errorf("CreateWebHook db err : %v", err)
		return errors.New("服务异常！请重试")
	}
	if !get {
		return errors.New("该用户未授权！")
	}
	if tu.AccessToken == "" {
		return errors.New("该用户未授权！")
	}

	tr := &pipeline.TRepo{}
	get, err = db.Where("openid = ? and deleted != 1", openid).Get(tr)
	if err != nil {
		return err
	}
	if !get {
		return fmt.Errorf("未找到仓库")
	}
	hs := comm.MainCfg.ServerConf.Host
	appinfo, err := GetsParamOAuthKey()
	if err != nil {
		core.Log.Errorf("ActiveRepo.GetsParamOAuthKey err : %v", err)
		return err
	}
	k, info := appinfo.DefAppInfo()
	backUrl := fmt.Sprintf("%s/api/repos/hooks/%s", hs, k)
	pwd := fmt.Sprintf(common.HookSecret, utils.NewXid(), utils.RandomString(6))
	cl, err := comm.GetThirdApi(k, info.SourceHost)
	if err != nil {
		core.Log.Errorf("ActiveRepo.GetThirdApi err : %v", err)
		return err
	}
	ch, err := cl.Repositories.CreateWebHooks(tu.AccessToken, tr.Namespace, tr.Path, backUrl, pwd)
	if err != nil {
		return errors.New("启用仓库失败,请检查仓库权限")
	}
	tr.HookId = strconv.Itoa(ch.Id)
	tr.HookSecret = pwd
	tr.Active = 1
	tr.UpdateTime = time.Now()
	_, err = db.Where("id = ?", tr.Id).Cols("hook_id,hook_secret,active,update_time").Update(tr)
	if err != nil {
		return errors.New("启用仓库失败,请重试")
	}

	return nil
}

// 关闭仓库
func CloseRepo(accessToken string, repo *pipeline.TRepo) error {
	appinfo, err := GetsParamOAuthKey()
	if err != nil {
		core.Log.Errorf("RefreshRepos.CloseRepo err : %v", err)
		return err
	}
	k, info := appinfo.DefAppInfo()
	cl, err := comm.GetThirdApi(k, info.SourceHost)
	if err != nil {
		core.Log.Errorf("CloseRepo.GetThirdApi err : %v", err)
		return err
	}
	i := 1
	for {
		if i > 10 {
			break
		} // 最多执行10次,加快响应速度
		hs, err := cl.Repositories.GetWebHooks(accessToken, repo.Namespace, repo.Path, i, 20)
		i++
		if err != nil {
			core.Log.Errorf("DeleteHooks oerr : %v", err)
			return fmt.Errorf("关闭仓库失败,请检查gitee仓库权限")
		}
		if len(hs) <= 0 {
			break
		} // 如果已经没有webhook了,结束循环
		for _, h := range hs {
			hos := comm.MainCfg.ServerConf.Host
			if h.Url != fmt.Sprintf("%s/api/repos/hooks/%s", hos, k) {
				continue
			}
			err = HookCloseRepo(accessToken, repo, h, k, info.SourceHost)
			if err != nil {
				core.Log.Errorf("DeleteHooks err : %v", err)
			}
		}
	}
	db := comm.DBMain.GetDB()
	repo.HookId = ""
	repo.Active = 0
	_, err = db.Where("id = ?", repo.Id).Cols("hook_id,active").Update(repo)
	if err != nil {
		return err
	}
	return nil
}

func HookCloseRepo(accessToken string, repo *pipeline.TRepo, h *thirdapi.RepositoryHook, info string, host string) error {
	cl, err := comm.GetThirdApi(info, host)
	if err != nil {
		return err
	}
	err = cl.Repositories.DeleteHooks(accessToken, repo.Namespace, repo.Path, strconv.Itoa(h.Id))
	if err != nil {
		return err
	}
	return nil
}

func GetRepos(param *repobean.ParamGetRepo, user *pipeline.TUser) (tRepos *dbcore.Page, errs error) {
	var args []interface{} // 多参数分页查询
	sqls := "select {{select}} from t_repo where t_repo.deleted != 1 "
	if !CheckUPermission(user, "admin") {
		sqls += "and id in (select repo_id from t_user_repo where user_id = ?) "
		args = append(args, user.Id)
	}
	if param.Q != "" {
		sqls += "AND full_name like ? "
		q := "%" + param.Q + "%"
		args = append(args, q)
	}
	if param.Namespace != "" {
		sqls += "AND namespace = ? "
		q := param.Namespace
		args = append(args, q)
	}
	sqls += "ORDER BY  t_repo.active DESC "
	tRpoList := make([]*pipeline.TRepo, 0)
	page, err := comm.DBMain.FindPages(&dbcore.PageGen{
		SQL:       sqls,
		Args:      args,
		CountCols: "t_repo.id",
		FindCols:  "t_repo.*",
	}, &tRpoList, param.Page, param.Size)
	if err != nil {
		return nil, err
	}
	return page, nil
}
